import request from '../utils/request'
import { GlobalData } from '/store/state'

/** 上传任务 */
interface UploadTask {
  /** 上传文件的请求地址 */
  uri: string
  /** 上传文件的请求方式 */
  method: 'POST' | 'PUT'
  /** 上传文件时候，headers 必须的键值 */
  headers: {
    'Content-Type': string
    'Content-Length': number
    'Content-Md5': string
    'Content-Disposition': string
    Accept?: 'application/json'
  }
  /** 上传时候的表单，如果是 NULL 则表示整个 Body 是二进制文件流，如果是对象，则构造 `application/form-data` 表单对象 */
  form: null | object
  /** 如果存在 `form` 表单信息，文件流所使用的 key 名称 */
  file_key: null | unknown
  /** 文件上传完成后所使用的文件节点 */
  node: string
  /* 文件上传后的地址 */
  url: string
}

// interface uploadRes {

// }

const mimeTypeMap = {
  jpeg: 'image/jpeg',
  jpg: 'image/jpeg',
  png: 'image/png',
  gif: 'image/gif',
  mp4: 'video/mp4',
}

export function getFileSize(filePath: string): Promise<boolean | number> {
  return new Promise((resolve, reject) => {
    wx.getFileInfo({
      filePath,
      success: ({ size }: { size: number }) => {
        resolve(size)
      },
      fail: () => {
        reject(false)
      },
    })
  })
}

/**
 * 创建上传任务
 */
async function createUploadTask(filePath: string, size?: number | boolean) {
  const ext = (filePath.toLowerCase().match(/\.(jpe?g|png|gif|mp4)$/i) || [])[1] as
    | 'png'
    | 'gif'
    | 'jpg'
    | 'jpeg'
    | 'mp4'
    | undefined
  if (!ext) return Promise.reject(`不支持的后缀: ${filePath}`)

  const isVideo = filePath.endsWith('mp4')
  const fs = wx.getFileSystemManager()
  if (!size) {
    size = await getFileSize(filePath)
    if (size === false) {
      return Promise.reject('无法获取文件大小')
    }
  }
  const info = await new Promise((resolve, reject) => {
    wx.getFileInfo({
      filePath,
      success: (result) => {
        resolve(result.digest)
      },
    })
  })

  let arrayBuffer
  try {
    arrayBuffer = fs.readFileSync(filePath)
    console.log(arrayBuffer)
  } catch (e) {
    console.error(e)
  }

  // wx.compressVideo

  // 图片安全检测
  let checkArrayBuffer: any = arrayBuffer
  let fileSize = size
  // 大于1M需要进行压缩
  if (!isVideo && fileSize > 1024 * 1000) {
    checkArrayBuffer = await new Promise((resolve, reject) => {
      wx.compressImage({
        src: filePath, // 图片路径
        quality: 50, // 压缩质量
        fail(err) {
          reject(err)
        },
        success(res) {
          wx.getFileInfo({
            filePath: res.tempFilePath,
            success(result) {
              fileSize = result.size
              resolve(fs.readFileSync(res.tempFilePath))
            },
            fail(err) {
              reject(err)
            },
          })
        },
      })
    })
  }

  if (GlobalData.access.secCheck && !isVideo) {
    if (fileSize > 1024 * 1000) {
      return Promise.reject('文件过大，暂不支持大文件发布')
    }

    try {
      await request.request('/wechat/mini-program/sec-img-check', {
        method: 'PUT',
        data: checkArrayBuffer,
      })
    } catch (error) {
      return Promise.resolve(error)
    }
  }

  const res = await request.request('/storage', {
    data: {
      filename: filePath,
      hash: info,
      size,
      mime_type: mimeTypeMap[ext],
      storage: { channel: 'public' },
    },
  })
  const task = res.data as UploadTask
  return Promise.resolve({ task, arrayBuffer })
}

export async function uploadFileRaw(
  filePath: string,
  fileSize?: number,
): Promise<{ uri: string; node: string }> {
  const res = await createUploadTask(filePath, fileSize)
  const { task, arrayBuffer } = res
  if (!task) {
    return Promise.reject(res)
  }

  task.headers.Accept = 'application/json'
  return new Promise((resolve, reject) => {
    wx.request({
      method: task.method,
      url: task.uri,
      data: arrayBuffer,
      header: task.headers,
      success: ({ data, statusCode }) => {
        if (statusCode < 200 || statusCode >= 300) return reject(data)
        task.uri = task.url
        resolve(task as { uri: string; node: string })
      },
      fail: (err) => {
        reject(err)
      },
    })
  })
}

/** 上传文件 */
export async function uploadFile(filePath: string, fileSize?: number): Promise<string> {
  const { node } = await uploadFileRaw(filePath, fileSize)

  return node
}

/** 上传文件 */
export async function uploadFileWithUrl(
  filePath: string,
  fileSize?: number,
): Promise<{ uri: string; node: string }> {
  return await uploadFileRaw(filePath, fileSize)
}

/** 上传文件(返回对象) */
export async function uploadFiles(filePath: string, fileSize?: number): Promise<any> {
  const { task, arrayBuffer } = await createUploadTask(filePath, fileSize)

  task.headers.Accept = 'application/json'
  return new Promise((resolve, reject) => {
    wx.request({
      method: task.method,
      url: task.uri,
      data: arrayBuffer,
      header: task.headers,
      success: ({ data, statusCode }) => {
        if (statusCode < 200 || statusCode >= 300) return reject(data)
        // 腾讯云上传接口没有返回 url, 所以使用第一步任务返回的地址
        task.uri = task.url
        resolve(task)
      },
      fail: (err) => {
        reject(err)
      },
    })
  })
}
